﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Xml.Linq;

namespace SharePointUtilitiesForDevelopers.Tests
{
    /// <summary>
    /// Test class for <see cref="SharePointXml"/>.
    /// </summary>
    [TestClass]
    public class SharePointXmlTest
    {
        private enum TestEnum
        {
            None,
            Red,
            Green,
            Blue
        }

        [TestMethod]
        public void ParseLookupId_parses_value_correctly()
        {
            var lookupString = "1;#USA";
            var actual = SharePointXml.ParseLookupId(lookupString);
            Assert.AreEqual(1, actual);
        }

        [TestMethod]
        public void ParseLookupId_returns_null_when_value_is_empty_string()
        {
            var lookupString = "";
            var actual = SharePointXml.ParseLookupId(lookupString);
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void ParseLookupId_returns_null_when_value_is_null()
        {
            var actual = SharePointXml.ParseLookupId(null);
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void GetAttributeAsGuid_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest attribute1='{E418F308-929E-4AE8-B2C2-62EB1B621908}'></unitTest>");
            var expected = new Guid("{E418F308-929E-4AE8-B2C2-62EB1B621908}");
            var actual = SharePointXml.GetAttributeAsGuid(element, "attribute1");
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsGuid_returns_empty_guid_when_attribute_is_not_present()
        {
            var element = XElement.Parse("<unitTest></unitTest>");
            var expected = Guid.Empty;
            var actual = SharePointXml.GetAttributeAsGuid(element, "attribute1");
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsGuid_returns_empty_guid_when_attribute_value_is_empty()
        {
            var element = XElement.Parse("<unitTest attribute1=''></unitTest>");
            var expected = Guid.Empty;
            var actual = SharePointXml.GetAttributeAsGuid(element, "attribute1");
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void GetAttributeAsGuid_throws_exception_when_attribute_contains_invalid_guid()
        {
            var element = XElement.Parse("<unitTest attribute1='xx-xx-xx'></unitTest>");
            SharePointXml.GetAttributeAsGuid(element, "attribute1");
        }

        [TestMethod]
        public void ParseXml_with_null_xml_returns_default_xml()
        {
            var actual = SharePointXml.ParseXml(null, "unitTest");
            var expected = "<unitTest />";
            Assert.IsNotNull(actual, "Did not return XElement");
            Assert.AreEqual(expected, actual.OuterXml);
        }

        [TestMethod]
        public void ParseXml_with_empty_string_returns_default_xml()
        {
            var actual = SharePointXml.ParseXml(string.Empty, "unitTest");
            var expected = "<unitTest />";
            Assert.IsNotNull(actual, "Did not return XElement");
            Assert.AreEqual(expected, actual.OuterXml);
        }

        [TestMethod]
        public void ParseXml_with_null_xml_returns_null_when_default_xml_is_null()
        {
            var actual = SharePointXml.ParseXml(null, null);
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void ParseXml_with_null_xml_returns_null_when_default_xml_is_empty_string()
        {
            var actual = SharePointXml.ParseXml(null, string.Empty);
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void GetElementValueAsString_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest>aValue</unitTest>");
            var actual = SharePointXml.GetElementValueAsString(element);
            Assert.AreEqual("aValue", actual);
        }

        [TestMethod]
        public void GetElementValueAsString_returns_empty_string_when_element_is_null()
        {
            var actual = SharePointXml.GetElementValueAsString(null);
            Assert.AreEqual(string.Empty, actual);
        }

        [TestMethod]
        public void GetElementValueAsBoolean_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest>true</unitTest>");
            var actual = SharePointXml.GetElementValueAsBoolean(element);
            Assert.AreEqual(true, actual);
        }

        [TestMethod]
        public void GetElementValueAsBoolean_returns_false_when_element_is_null()
        {
            var actual = SharePointXml.GetElementValueAsBoolean(null);
            Assert.AreEqual(false, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void GetElementValueAsBoolean_throws_exception_when_element_value_is_unexpected()
        {
            var element = XElement.Parse("<unitTest>falser</unitTest>");
            SharePointXml.GetElementValueAsBoolean(element);
        }

        [TestMethod]
        public void GetElementValueAsInteger_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest>2</unitTest>");
            var actual = SharePointXml.GetElementValueAsNullableInteger(element);
            Assert.AreEqual(2, actual);
        }

        [TestMethod]
        public void GetElementValueAsInteger_returns_null_when_element_is_null()
        {
            var actual = SharePointXml.GetElementValueAsNullableInteger(null);
            Assert.AreEqual(null, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void GetElementValueAsInteger_throws_exception_when_element_value_is_unexpected()
        {
            var element = XElement.Parse("<unitTest>f1</unitTest>");
            SharePointXml.GetElementValueAsNullableInteger(element);
        }

        [TestMethod]
        public void GetChildElement_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild></unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElement(element, "unitTestChild");
            Assert.IsNotNull(actual);
            Assert.AreEqual("unitTestChild", actual.Name);
        }

        [TestMethod]
        public void GetChildElement_returns_null_when_element_is_null()
        {
            var actual = SharePointXml.GetChildElement(null, string.Empty);
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void GetChildElement_returns_null_when_not_found()
        {
            var element = XElement.Parse("<unitTest><unitTestChildTwo></unitTestChildTwo></unitTest>");
            var actual = SharePointXml.GetChildElement(element, "unitTestChild");
            Assert.IsNull(actual);
        }

        [TestMethod]
        public void GetChildElement_returns_correct_element()
        {
            var element = XElement.Parse("<unitTest><unitTestChild></unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElement(element, "unitTestChild");
            Assert.IsNotNull(actual);
            Assert.AreEqual("unitTestChild", actual.Name);
        }

        [TestMethod]
        public void GetChildElement_returns_correct_element_when_differs_by_case()
        {
            var element = XElement.Parse("<unitTest><unitTestChild></unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElement(element, "UnitTestChild");
            Assert.IsNotNull(actual);
            Assert.AreEqual("unitTestChild", actual.Name);
        }

        [TestMethod]
        public void GetChildElementValueAsString_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild>aValue</unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElementValueAsString(element, "unitTestChild");
            Assert.AreEqual("aValue", actual);
        }

        [TestMethod]
        public void GetChildElementValueAsString_returns_empty_string_when_element_is_null()
        {
            var actual = SharePointXml.GetChildElementValueAsString(null, string.Empty);
            Assert.AreEqual(string.Empty, actual);
        }

        [TestMethod]
        public void GetChildElementValueAsBoolean_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild>true</unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElementValueAsBoolean(element, "unitTestChild");
            Assert.AreEqual(true, actual);
        }

        [TestMethod]
        public void GetChildElementAttributeValueAsBoolean_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild attribute1='true'></unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElementAttributeValueAsBoolean(element, "unitTestChild", "attribute1");
            Assert.AreEqual(true, actual);
        }

        [TestMethod]
        public void GetChildElementValueAsInteger_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild>42</unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElementValueAsNullableInteger(element, "unitTestChild");
            Assert.AreEqual(42, actual);
        }

        [TestMethod]
        public void GetChildElementAttributeValueAsInteger_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest><unitTestChild attribute1='42'></unitTestChild></unitTest>");
            var actual = SharePointXml.GetChildElementAttributeValueAsNullableInteger(element, "unitTestChild", "attribute1");
            Assert.AreEqual(42, actual);
        }

        [TestMethod]
        public void ParseUniqueId_parses_correctly()
        {
            var uniqueIdString = "1;#{F8969181-C1DD-41a9-B349-833F469D51C0}";
            var expected = new Guid("{F8969181-C1DD-41a9-B349-833F469D51C0}");
            var actual = SharePointXml.ParseUniqueId(uniqueIdString);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void ParseUniqueId_throws_exception_when_format_is_invalid()
        {
            var uniqueIdString = "1;{F8969181-C1DD-41a9-B349-833F469D51C0}";
            var expected = new Guid("{F8969181-C1DD-41a9-B349-833F469D51C0}");
            var actual = SharePointXml.ParseUniqueId(uniqueIdString);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ParseUrl_parses_correctly()
        {
            var urlString = "http://unittest, A unit test";
            var expected = "http://unittest";
            var actual = SharePointXml.ParseUrl(urlString);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ParseUrlDescription_parses_correctly()
        {
            var urlString = "http://unittest, A unit test";
            var expected = "A unit test";
            var actual = SharePointXml.ParseUrlDescription(urlString);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void SplitValue_returns_correct_value()
        {
            var itemString = "http://unittest, A unit test";
            var result = SharePointXml.SplitValue(itemString, ", ", 2);
            Assert.AreEqual(2, result.Length);
            Assert.AreEqual("http://unittest", result[0]);
            Assert.AreEqual("A unit test", result[1]);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SplitValue_throws_exception_when_separator_is_null()
        {
            var itemString = "item1;#item2";
            SharePointXml.SplitValue(itemString, null, 2);
        }

        [TestMethod]
        public void SplitValue_splits_correctly_when_length_is_not_specified()
        {
            var itemString = "item1;#item2;#item3";
            var actual = SharePointXml.SplitValue(itemString, ";#", null);
            Assert.AreEqual(3, actual.Length);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void SplitValue_throws_exception_when_length_is_not_same_as_expected()
        {
            var itemString = "item1;#item2;#item3";
            SharePointXml.SplitValue(itemString, ";#", 2);
        }

        [TestMethod]
        public void GetAttribute_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest someAttribute=\"true\"></unitTest>");
            var actual = SharePointXml.GetAttribute(element, "someAttribute");
            Assert.IsNotNull(actual);
            Assert.AreEqual("true", actual.Value);
        }

        [TestMethod]
        public void GetAttribute_returns_correct_value_when_differs_by_case()
        {
            var element = XElement.Parse("<unitTest someAttribute=\"true\"></unitTest>");
            var actual = SharePointXml.GetAttribute(element, "SomeAttribute");
            Assert.IsNotNull(actual);
            Assert.AreEqual("true", actual.Value);
        }

        [TestMethod]
        public void GetAttributeAsString_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest attribute1=\"value1\" />");
            var attributeName = "attribute1";
            var expected = "value1";
            var actual = SharePointXml.GetAttributeAsString(element, attributeName);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsString_returns_empty_string_when_not_found()
        {
            var element = XElement.Parse("<unitTest attribute1=\"value1\" />");
            var attributeName = "attribute2";
            var expected = "";
            var actual = SharePointXml.GetAttributeAsString(element, attributeName);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsBoolean_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest attribute1=\"true\" />");
            var attributeName = "attribute1";
            var actual = SharePointXml.GetAttributeAsBoolean(element, attributeName);
            Assert.IsTrue(actual);
        }

        [TestMethod]
        public void GetAttributeAsBoolean_returns_false_when_not_found()
        {
            var element = XElement.Parse("<unitTest attribute1=\"true\" />");
            var attributeName = "attribute2";
            var actual = SharePointXml.GetAttributeAsBoolean(element, attributeName);
            Assert.IsFalse(actual);
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void GetAttributeAsBoolean_throws_exception_when_format_is_not_valid()
        {
            var element = XElement.Parse("<unitTest attribute1=\"bad\" />");
            var attributeName = "attribute1";
            var actual = SharePointXml.GetAttributeAsBoolean(element, attributeName);
            Assert.IsFalse(actual);
        }

        [TestMethod]
        public void GetAttributeAsEnumByName_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest attribute1=\"Red\" />");
            var attributeName = "attribute1";
            var defaultValue = TestEnum.None;
            var expected = TestEnum.Red;
            var actual = SharePointXml.GetAttributeAsEnum(element, attributeName, defaultValue, false);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetAttributeAsEnumByName_throws_exception_when_not_found()
        {
            var element = XElement.Parse("<unitTest attribute1=\"DoesNotExist\" />");
            var attributeName = "attribute1";
            var defaultValue = TestEnum.None;
            var expected = TestEnum.Green;
            var actual = SharePointXml.GetAttributeAsEnum(element, attributeName, defaultValue, false);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsEnumByName_returns_default_value_when_not_found()
        {
            var element = XElement.Parse("<unitTest attribute1=\"DoesNotExist\" />");
            var attributeName = "attribute1";
            var defaultValue = TestEnum.Blue;
            var expected = TestEnum.Blue;
            var actual = SharePointXml.GetAttributeAsEnum(element, attributeName, defaultValue, true);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetAttributeAsEnum_returns_correct_value()
        {
            var element = XElement.Parse("<unitTest attribute1=\"2\" />");
            var attributeName = "attribute1";
            var defaultValue = TestEnum.None;
            var expected = TestEnum.Green;
            var actual = SharePointXml.GetAttributeAsEnum(element, attributeName, defaultValue, false);
            Assert.AreEqual(expected, actual);
        }
    }
}
